package com.devshephard.jucks.SingleDemo.SingleInClazz;


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 以懒汉式单例-双重检测锁模式,测试两个都为反射生成的对象的单例中的标志位破坏问题
 */
public class LazyManClazzTest_4 {

    private static volatile LazyManClazzTest_4 lazyManlaDoubleCheck; //加入volatile关键字,防止指令重排的问题

    private static boolean flag = false;  //解决反射的第二种方式,加锁和设置标志位,但是当两个对象都是通过反射生成,则同样会出现问题

    //单例模式必须构造器私有
    private LazyManClazzTest_4() {

                  synchronized (LazyManClazzTest_4.class){
                      if(flag == false){
                         flag = true;
                      }else{
                          throw new RuntimeException("不要试图用反射破坏单例！");
                      }
                  }

    }

    public static LazyManClazzTest_4 getInstance(){
        if(lazyManlaDoubleCheck == null){ //当lazyMan对象为空,则表明没有生成到内存空间中
            synchronized (LazyManClazzTest_4.class){ //为类加锁,保证多线程下线程安全
                if(lazyManlaDoubleCheck == null){
                    lazyManlaDoubleCheck = new LazyManClazzTest_4();
                }
            }
        }
        return lazyManlaDoubleCheck;
    };

    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        Field flag = LazyManClazzTest_4.class.getDeclaredField("flag");
        flag.setAccessible(true);

        //使用反射生成对象
        Constructor<LazyManClazzTest_4> declaredConstructor = LazyManClazzTest_4.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyManClazzTest_4 instance1 = declaredConstructor.newInstance();

        flag.set(instance1,false); //将标志位设置为false,解决反射问题

        LazyManClazzTest_4 instance2 = declaredConstructor.newInstance();

        //两个对象的hashCode都不相同,说明单例模式被破坏
        System.out.println(instance1.hashCode());
        System.out.println(instance2.hashCode());
    }

}
